﻿using System;
using System.Collections.Generic;
using System.Collections;
using UnityEngine;

namespace FrameWork
{

    public class AssetInfo
    {
        private UnityEngine.Object _Object;
        public Type AssetType { get; set; }
        public string Path { get; set; }
        public int RefCount { get; set; }
        public bool IsLoaded 
        { 
            get{
                return null != _Object;
            }
        }

        public UnityEngine.Object AssetObject
        {
            get
            {
                if (null == _Object)
                {
                    _ResourceLoad();
                }
                return _Object;
                
            }
        }

        //协程异步加载(协程加载)
        public IEnumerator GetCoroutineObject(Action<UnityEngine.Object> _loaded)
        {
            while(true)
            {
                yield return null;
                if (null == _Object)
                {
                     //yield return null;
                     _ResourceLoad();
                    yield return null; //停顿一帧
                }
//                 else
//                 {
                if (null != _loaded)
                {
                    _loaded(_Object);
                }
/*                }*/
                yield break;
            }
        }

        private void _ResourceLoad()
        {
            try
            {
                _Object = Resources.Load(Path);
                if (null == _Object)
                {
                    Debug.Log("Resources Load Failure! path:" + Path);
                }
            }
            catch (System.Exception e)
            {
                Debug.Log(e.ToString());
            }
        }

        public IEnumerator GetAsyncObject(Action<UnityEngine.Object> _loaded)
        {
             return GetAsyncObject(_loaded, null);
        }

        public IEnumerator GetAsyncObject(Action<UnityEngine.Object> _loaded,Action<float> _progress)
        {
            if (null != _Object)
            {
                _loaded(_Object);
                yield break;
            }
            UnityEngine.ResourceRequest _resRequest =  Resources.LoadAsync(Path);
// 
//             while(_resRequest.progress < 0.9)
//             {
//                 if (null != _progress)
//                 {
//                     _progress(_resRequest.progress);
//                     yield return null;
//                 }
//             }
// 
//             while (!_resRequest.isDone)
//             {
//                 if (null != _progress)
//                 {
//                     _progress(_resRequest.progress);
//                     yield return null;
//                 }
//             }

            _Object = _resRequest.asset;
            if (null != _loaded)
            {
                _loaded(_Object);
            }

            yield return _resRequest;

        }

    }

    public class ResManager : Singleton<ResManager>
    {

        private Dictionary<string, AssetInfo> dicAssetInfo;

        public override void Init()
        {
            dicAssetInfo = new Dictionary<string, AssetInfo>();
        }

        #region Load Resources & Instantitae Object

        public UnityEngine.Object LoadInstance(string _path)
        {
            UnityEngine.Object _obj = Load(_path);
            return Instantiate(_obj);
        }

        //异步协程实例化
        public void LoadCoroutineInstance(string _path,Action<UnityEngine.Object> _loaded)
        {
            LoadCoroutine(_path, (_obj) => { Instantiate(_obj, _loaded); });

        }

        //异步加载实例化
        public void LoadAsyncInstance(string _path, Action<UnityEngine.Object> _loaded)
        {
            LoadAsync(_path, (_obj) => { Instantiate(_obj, _loaded); });
        }

        //异步加载实例化
        public void LoadAsyncInstance(string _path, Action<UnityEngine.Object> _loaded, Action<float> _pregress)
        {
            LoadAsync(_path, (_obj) => { Instantiate(_obj, _loaded); },_pregress);
        }

        #endregion

        #region Load Resources //即时加载

        public UnityEngine.Object Load(string _path)
        {
            AssetInfo _assetInfo = GetAssetInfo(_path);
            if(null != _assetInfo)
            {
                return _assetInfo.AssetObject;
            }
            return null;
        }
        #endregion

        #region  Load Coroutine Resource 协程加载

        public void LoadCoroutine(string _path,Action<UnityEngine.Object> _loaded)
        {
            AssetInfo _assetInfo = GetAssetInfo(_path,_loaded);
            if(null != _assetInfo)
            {
                CoroutineController.Instance.StartCoroutine(_assetInfo.GetCoroutineObject(_loaded));
            }
        }

        #endregion

        #region Load Async Resources 异步加载

        public void LoadAsync(string _path,Action<UnityEngine.Object> _loaded)
        {
            LoadAsync(_path,_loaded,null);
        }

        public void LoadAsync(string _path, Action<UnityEngine.Object> _loaded,Action<float> _pregress)
        {
            AssetInfo _assetInfo = GetAssetInfo(_path,_loaded);
            if(null != _assetInfo)
            {
                CoroutineController.Instance.StartCoroutine(_assetInfo.GetAsyncObject(_loaded));
            }
        }
        #endregion


        private UnityEngine.Object Instantiate(UnityEngine.Object _obj)
        {
            return Instantiate(_obj,null);
        }

        public UnityEngine.Object Instantiate(UnityEngine.Object _obj,Action<UnityEngine.Object> _loaded)
        {
            UnityEngine.Object _reObj = null;
            if(null != _obj)
            {
                _reObj = MonoBehaviour.Instantiate(_obj);
                if(null != _reObj)
                {
                    if(null != _loaded)
                    {
                        _loaded(_reObj);
                    }
                    return _reObj;
                }
                else
                {
                    Debug.LogError("Error: null _loaded...");
                }
            }
            else
            {
                Debug.LogError("Error: null Instance _reObj..");
            }
            return null;
        }

        private AssetInfo GetAssetInfo(string _path)
        {
            return GetAssetInfo(_path,null);
        }

        private AssetInfo GetAssetInfo(string _path,Action<UnityEngine.Object> _loaded)
        {
            if (string.IsNullOrEmpty(_path))
            {
                Debug.Log("error:null path name");
                if (null != _loaded)
                {
                    _loaded(null);
                }
            }

            //资源加载工作
            AssetInfo _assetInfo = null;
            if (!dicAssetInfo.TryGetValue(_path, out _assetInfo))
            {
                _assetInfo = new AssetInfo();
                _assetInfo.Path = _path;
                dicAssetInfo.Add(_path, _assetInfo);
            }
            _assetInfo.RefCount++;
            return _assetInfo;
        }

        /// <summary>
        /// 加载并实例化
        /// </summary>
        /// <param name="_path"></param>
        /// <returns></returns>
//         public UnityEngine.Object LoadInstance(string _path)
//         {
//             UnityEngine.Object _reObj = null;
//             UnityEngine.Object _Obj = null;
//             _reObj = Load(_path);
//             if (_reObj != null) //资源加载失败
//             {
//                 _Obj = MonoBehaviour.Instantiate(_reObj);
//                 if (null != _Obj)
//                 {
//                     return _Obj;
//                 }
//                 else
//                 {
//                     Debug.LogError("Error: NULL Instance _Obj");
//                 }
//             }
//             else
//             {
//                 Debug.LogError("Error: NULL resource load return obj");
//             }
//             return null;
//         }

        public void LoadInstance(string _path,Action<UnityEngine.Object> _loaded)
        {
            LoadInstance(_path,_loaded,null);
        }

        public void LoadInstance(string _path, Action<UnityEngine.Object> _loaded,Action<float> _progress)
        {
            Load(_path,(_obj) => {
                UnityEngine.Object _reObj = null;
                if (_obj != null) //资源加载失败
                {
                   _reObj = MonoBehaviour.Instantiate(_obj);
                    if(null != _reObj)
                    {
                        if (null != _loaded)
                            _loaded(_reObj);
                        else
                            Debug.LogError("Error: NULL loadeds");
                    }
                    else
                    {
                        Debug.LogError("Error: NULL Instantiate");
                    }
                }
                else
                {
                    Debug.LogError("Error: NULL resource load return obj");
                }
            } ,_progress);
        }

//         public UnityEngine.Object Load(string _path)
//         {
//             UnityEngine.Object _obj = null;
//              if(string.IsNullOrEmpty(_path))
//             {
//                 Debug.Log("error:null path name");
//                 return null;
//             }
// 
//             //资源加载工作
// 
//             return _obj;
//         }

        public void Load(string _path, Action<UnityEngine.Object> _loaded)
        {
            Load(_path,_loaded,null);
        }

        /// <summary>
        /// 实际加载工作
        /// </summary>
        /// <param name="_path"></param>
        /// <param name="_loaded"></param>
        /// <param name="_progress"></param>
        public void Load(string _path,Action<UnityEngine.Object> _loaded,Action<float> _progress)
        {
            if(string.IsNullOrEmpty(_path))
            {
                Debug.Log("error:null path name");
                if(null != _loaded)
                {
                   //调用失败
                    _loaded(null);
                }
            }

            //资源加载工作
            AssetInfo _assetInfo = null;
            if (!dicAssetInfo.TryGetValue(_path, out _assetInfo))
            {
                _assetInfo = new AssetInfo();
                _assetInfo.Path = _path;
                dicAssetInfo.Add(_path, _assetInfo);
            }
            _assetInfo.RefCount++;
            CoroutineController.Instance.StartCoroutine(_assetInfo.GetAsyncObject(_loaded,_progress));
        }

    }
}